//
//  YWDownloadManager3.m
//  videoTest3
//
//  Created by jun peng on 2022/8/15.
//

#import "YWDownloadManager3.h"

#import "YWDownloadStatus3.h"
#import "YWDownloadDataTaskTool.h"

#define downloadingArrayMaxNum 3

@interface YWDownloadManager3 ()

@property (nonatomic,strong)NSMutableArray *group;//到时VC直接从这个group获取数据、第一次从数据库获取组成group、之后通过有新任务过来就添加一次 <装的是status>

@property(nonatomic,copy) void(^groupArrayBlock)(NSArray *group);//当group数据有变化的话都通过这个block告诉VC

@property(nonatomic,assign)BOOL isHaveBeginDataTask; //是否已经调用了beginDataTask方法

@property(nonatomic,strong)NSMutableDictionary *dataTaskToolDict;//通过YWDownloadStatus3的用网上videoURL作为key、找到对应的dataTask（有了这个到时要优先暂停继续那些拿任务去处理通过key直接拿就行、就不用遍历数组之类的）<装的是Tool>

@property(nonatomic,strong)NSMutableArray *downloadingToolArray; //正在下载数组（对于规定下载个数、和按等待中的优先按钮后、谁被第一个踢出去很重要）<装的是Tool>

@property(nonatomic,strong)NSMutableArray *waitingToolArray; //等待中数组(对于排队顺序下一个谁去下载很重要) <装的是Tool>

@end



@implementation YWDownloadManager3

#pragma mark - 以下方法要处理的操作
//改变枚举、数据库、字典、数组、文件夹、group、Tool操作

//单例
SingleM(downloadManager)

//1、app一进来就要调用开启任务了、获取数据库只有一次机会、就在这里
//2、在退出app之前的模型是怎么样就归位怎么样、包括正在任务中和完成任务的、就算一个任务也没有全新的也有初始化字典数组等东西
-(void)beginDataTask{
    
    //这方法只能调用一次
    if (self.isHaveBeginDataTask == YES) {
        return;
    }
    
    self.isHaveBeginDataTask = YES;
    
    //这里先获取数据库
    NSArray *downloadinigStatusArray = [YWDownloadDataBaseTool getDownloadingAllNewsDataStatus];
    NSArray *finishDownloadStatusArray = [YWDownloadDataBaseTool getFinishAllNewsDataStatus];
    
    //按日期排序
    downloadinigStatusArray = [YWDownloadStatus3 compareDateWithArray:downloadinigStatusArray];
    finishDownloadStatusArray = [YWDownloadStatus3 compareDateWithArray:finishDownloadStatusArray];

    //组建group
    YWSectionGroupStatus *sectionStatus0 = self.group[0];
    YWSectionGroupStatus *sectionStatus1 = self.group[1];
    sectionStatus0.statusArray = [NSMutableArray arrayWithArray:downloadinigStatusArray];
    sectionStatus1.statusArray = [NSMutableArray arrayWithArray:finishDownloadStatusArray];
        
    //解决“退出了app重新进来”、任务肯定不存在字典任务中
    for (YWDownloadStatus3 *status in sectionStatus0.statusArray) {
        
        //1、不管三七二十一先加入字典、创建YWDownloadDataTaskStatus、并保存到字典 - -
        YWDownloadDataTaskTool *dataTaskTool = [[YWDownloadDataTaskTool alloc] init];
        dataTaskTool.status = status;
        [self.dataTaskToolDict setObject:dataTaskTool forKey:status.VideoUrl];
            
        //根据枚举决定去哪两个数组
        switch (status.downloadType) {
            case YWDownloadType_Waiting:
            {
                [self.waitingToolArray addObject:dataTaskTool];
                
            }
                break;
            case YWDownloadType_Downloading:
            {
                [self.downloadingToolArray addObject:dataTaskTool];
                
                //开始下载
                [dataTaskTool resumeDataTask];
                
            }
                break;
                
            default:
                break;
        }
            
    }
    
}

//在下载页VC的viewDidload调用、group有变化都会返回block、下载页VC只需要引用这个回传的group后直接刷新
-(void)getDataTaskArray:(void(^)(NSArray *group))groupArrayBlock{
    
    self.groupArrayBlock = groupArrayBlock;
    
    //可以弄个BOOL属性作为是否开启了任务、假如用户调用createOneDataTaskWithStatus之前没有先调用beginDataTask就布尔值为NO、就内部先帮你调用beginDataTask再走createOneDataTaskWithStatus里面内容
    if (self.isHaveBeginDataTask == NO) {
        [self beginDataTask];
    }
    
    //这里传一次group给VC (VC想拿group就直接调用这个方法拿group就可以了、现在group都交给Manager处理、VC不需要处理数据了、假如其它地方导致group数据改变也会通过block告诉VC的)
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
    
}

//创建了一个任务
-(void)createOneDataTaskWithStatus:(YWDownloadStatus3 *)status{
    
    //可以弄个BOOL属性作为是否开启了任务、假如用户调用createOneDataTaskWithStatus之前没有先调用beginDataTask就布尔值为NO、就内部先帮你调用beginDataTask再走createOneDataTaskWithStatus里面内容
    if (self.isHaveBeginDataTask == NO) {
        [self beginDataTask];
    }
    
    //为了严谨要再一次确认这个任务是全新不在数据库的、这操作不会花太多时间的
    [YWDownloadManager3 judgeStatusExistInDataBase:status.VideoUrl ifNoExist:^{
        
        //头一次全新的 （不存在字典任务中、不存在数据库中、枚举waiting等待分配是否转变为枚举downloading）、可能需要也可能不需要resume
        
        //1-2、创建YWDownloadDataTaskTool、并保存到字典
        YWDownloadDataTaskTool *dataTaskTool = [[YWDownloadDataTaskTool alloc] init];
        dataTaskTool.status = status;
        [self.dataTaskToolDict setObject:dataTaskTool forKey:status.VideoUrl];
        
       
        if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
            dataTaskTool.status.downloadType = YWDownloadType_Downloading3;
            [self.downloadingToolArray addObject:dataTaskTool];
            
            //开启下载
            [dataTaskTool resumeDataTask];
        }
        else{
        
            dataTaskTool.status.downloadType = YWDownloadType_Waiting3;
            [self.waitingToolArray addObject:dataTaskTool];
            
            
        }
        
        //把新的模型添加到数据库
        [YWDownloadDataBaseTool addDownloadingStatus: dataTaskTool.status];
        
        //回传block数组group
        YWSectionGroupStatus *sectionStatus0 = self.group[0];
        [sectionStatus0.statusArray addObject:dataTaskTool.status];
        if (self.groupArrayBlock) {
            self.groupArrayBlock(self.group);
        }
        
    }];
   
    
}

//继续一个任务 (包含按暂停和下载失败按钮)
-(void)continueOneDataTaskWithStatus:(YWDownloadStatus3 *)status{
    
//按了暂停中：若正在播放数组还不满3个、就加入正在播放数组、否则加入正在等待数组
    
    YWDownloadDataTaskTool *dataTaskTool = self.dataTaskToolDict[status.VideoUrl];
    
    if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
        
        //正在播放数组还不满3个、就加入正在播放数组
        dataTaskTool.status.downloadType = YWDownloadType_Downloading3;
        [self.downloadingToolArray addObject:dataTaskTool];
        
        //继续播放
        [dataTaskTool resumeDataTask];
    }
    else{
        
        //否则加入正在等待数组
        dataTaskTool.status.downloadType = YWDownloadType_Waiting3;
        [self.waitingToolArray addObject:dataTaskTool];
    }
    
    //处理数据库
    [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool.status];
    
    
    //回传block数组group
    //假如group对象和字典里的对象是相同对象、上面已经改了字典里的对象的属性、这里不用再对group里面的对象操作、直接刷新就行
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
    
    
}

//从等待中优先播放一个任务
-(void)advanceOneDataTaskWithStatus:(YWDownloadStatus3 *)status{
    
    YWDownloadDataTaskTool *dataTaskTool = self.dataTaskToolDict[status.VideoUrl];
    
    //修改枚举
    dataTaskTool.status.downloadType = YWDownloadType_Downloading3;
    
    //把这一个任务直接加入正在播放数组（不需要判断正在播放数组是不是满3个了、直接加入就行、因为肯定满3个才会有等待中按钮可以按）
    [self.downloadingToolArray addObject:dataTaskTool];
    
    //移除等待中数组的
    [self.waitingToolArray removeObject:dataTaskTool];
    
    //处理数据库
    [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool.status];
    
    //继续播放
    [dataTaskTool resumeDataTask];

    
    //加入了正在播放数组之后、再判断正在播放数组是不是大于3个了
    if (self.downloadingToolArray.count > downloadingArrayMaxNum) {
        
        //假如正在播放数组是不是大于等于3个了、就移除第0个B、并让它枚举变成等待中、并将B加入等待中数组、暂停B播放
        
        YWDownloadDataTaskTool *dataTaskTool2 = self.downloadingToolArray[0];
        dataTaskTool2.status.downloadType = YWDownloadType_Waiting3;
        [self.downloadingToolArray removeObjectAtIndex:0];
        [self.waitingToolArray addObject:dataTaskTool2];
        
        //处理数据库
        [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool2.status];
        
        //暂停播放
        [dataTaskTool2 pauseDataTask];
    }
    
    
    //回传block数组group
    //假如group对象和字典里的对象是相同对象、上面已经改了字典里的对象的属性、这里不用再对group里面的对象操作、直接刷新就行
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
    
}

//暂停一个任务
-(void)pauseOneDataTaskWithStatus:(YWDownloadStatus3 *)status{
    
//按了下载中：变成暂停、从下载中数组移除、看正在下载中数组满不满3个、不满就看等待中数组存不存在数据有就抽取一个加入正在下载的数组
    
    YWDownloadDataTaskTool *dataTaskTool = self.dataTaskToolDict[status.VideoUrl];
    
    //暂停播放
    [dataTaskTool pauseDataTask];
    
    //枚举变成暂停中、移除正在下载数组、不需要加入等待中数组
    dataTaskTool.status.downloadType = YWDownloadType_Pause3;
    
    //处理数据库
    [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool.status];
    
    
    [self.downloadingToolArray removeObject:dataTaskTool];
    
    
    
    
    //暂停之后，发现目前加载中数组不满3个就从正在等待数组抽取1个来填、、、并且要修改其枚举为‘正在下载’
    if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
        //前提条件是等待中数组要有数据
        if (self.waitingToolArray.count>0) {
            
            //就拿第一个数据去移动到正在下载中数组
            YWDownloadDataTaskTool *dataTaskTool2 = self.waitingToolArray[0];
            dataTaskTool2.status.downloadType = YWDownloadType_Downloading3;
            [self.downloadingToolArray addObject:dataTaskTool2];
            [self.waitingToolArray removeObjectAtIndex:0];
            
            //处理数据库
            [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool2.status];
            
            //开启播放
            [dataTaskTool2 resumeDataTask];
             
        }
    }
    //回传block数组group
    //假如group对象和字典里的对象是相同对象、上面已经改了字典里的对象的属性、这里不用再对group里面的对象操作、直接刷新就行
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
}

//删除了一个正在中的任务
-(void)removeOneDownloadingDataTaskWithStatus:(YWDownloadStatus3 *)status{
    //从字典移除、从下载中数组移除、从等待中数组移除
    YWDownloadDataTaskTool *dataTaskTool = self.dataTaskToolDict[status.VideoUrl];
    
    if (dataTaskTool == nil) {
        return;
    }
    
//    //先暂停下载先
//    [dataTaskTool pauseDataTask];
    
    //删除任务、永久不再下载
    [dataTaskTool removeDataTask];
    
    //从字典移除任务
    [self.dataTaskToolDict removeObjectForKey:dataTaskTool.status.VideoUrl];
    
    //从数组移除任务
    [self removeTool:dataTaskTool fromArray:self.downloadingToolArray];
    [self removeTool:dataTaskTool fromArray:self.waitingToolArray];;
    
    
    //处理数据库
    [YWDownloadDataBaseTool removeDownloadingStatus:dataTaskTool.status];

    //修改group
    YWSectionGroupStatus *sectionStatus0 = self.group[0];
    [sectionStatus0.statusArray removeObject:dataTaskTool.status];
    
    //发送通知改badgeValue
    [[NSNotificationCenter defaultCenter] postNotificationName:YWGetDownloadBadgeValueNote object:self userInfo:nil];
    
    //发送通知改变KLineCheatsVideoListCell状态
    [[NSNotificationCenter defaultCenter] postNotificationName:YWChangeKLineCheatsVideoListTypeNote object:self userInfo:@{YWVideoUrlKey:status.VideoUrl,YWKLineCheatsVideoListTypeKey:@(YWKLineCheatsVideoList_NoDownload3)}];
    
    
    
    //完成了一个、就自动下载下一个
    if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
        //前提条件是等待中数组要有数据
        if (self.waitingToolArray.count>0) {
            
            //就拿第一个数据去移动到正在下载中数组
            YWDownloadDataTaskTool *dataTaskTool2 = self.waitingToolArray[0];
            dataTaskTool2.status.downloadType = YWDownloadType_Downloading3;
            [self.downloadingToolArray addObject:dataTaskTool2];
            [self.waitingToolArray removeObjectAtIndex:0];
            
            //处理数据库
            [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool2.status];
            
            //开启播放
            [dataTaskTool2 resumeDataTask];
             
        }
    }
    
    //回传block数组group
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }

}

///Users/junpeng/Library/Developer/CoreSimulator/Devices/BD64FAD8-C710-4CA4-A7FE-31AD6C20E3B5/data/Containers/Data/Application/B840AA9B-B822-4074-BDA2-B5FA5D1D40A5/Library/Caches/Downloading/2022081918364241.mp4
//CB38ED0F-A060-4BC1-8135-5BBEDC91CEF6
//删除了一个完成了的任务
-(void)removeOneFinishDataTaskWithStatus:(YWDownloadStatus3 *)status{
    
    //处理数据库
    [YWDownloadDataBaseTool removeFinishStatus:status];
    
    //移除文件
    NSError *error2 = nil;
    if ([[NSFileManager defaultManager] fileExistsAtPath:status.fullPath]) {
         [[NSFileManager defaultManager] removeItemAtPath:status.fullPath error:&error2];
        if (error2 == nil) {
            YWLog(@"移除无效视频文件成功");
        }
        else{
            YWLog(@"移除无效视频文件失败");
        }
    }
    
    
    //修改group
    YWSectionGroupStatus *sectionStatus1 = self.group[1];
    [sectionStatus1.statusArray removeObject:status];
    
    //回传block数组group
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }

    
    //发送通知改变KLineCheatsVideoListCell状态
    [[NSNotificationCenter defaultCenter] postNotificationName:YWChangeKLineCheatsVideoListTypeNote object:self userInfo:@{YWVideoUrlKey:status.VideoUrl,YWKLineCheatsVideoListTypeKey:@(YWKLineCheatsVideoList_NoDownload3)}];
    
}

//下载一个任务完成通知
-(void)finishDownloadNote:(NSNotification *)notification{
    
    //拿出模型
    YWDownloadStatus3 *status = notification.userInfo[@"YWDownloadStatusKey"];

    YWDownloadDataTaskTool *dataTaskTool = [self.dataTaskToolDict objectForKey:status.VideoUrl];
    if (dataTaskTool == nil) {
        return;
    }
    
    [self.dataTaskToolDict removeObjectForKey:dataTaskTool.status.VideoUrl];
    
    //从数组移除任务
    [self removeTool:dataTaskTool fromArray:self.downloadingToolArray];
    [self removeTool:dataTaskTool fromArray:self.waitingToolArray];;
    
    //修改group
    YWSectionGroupStatus *sectionStatus0 = self.group[0];
    YWSectionGroupStatus *sectionStatus1 = self.group[1];
    [sectionStatus0.statusArray removeObject:dataTaskTool.status];
    [sectionStatus1.statusArray addObject:dataTaskTool.status];
    
    //发送通知改badgeValue
    [[NSNotificationCenter defaultCenter] postNotificationName:YWGetDownloadBadgeValueNote object:self userInfo:nil];
    
    //发送通知改变KLineCheatsVideoListCell状态
    [[NSNotificationCenter defaultCenter] postNotificationName:YWChangeKLineCheatsVideoListTypeNote object:self userInfo:@{YWVideoUrlKey:status.VideoUrl,YWKLineCheatsVideoListTypeKey:@(YWKLineCheatsVideoListD_Finish3)}];
    
    //这里就不需要枚举、数据库、通知了、因为YWDownloadDataTaskTool里面的完成回调里面已经做了
    
    //完成了一个、就自动下载下一个
    if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
        //前提条件是等待中数组要有数据
        if (self.waitingToolArray.count>0) {
            
            //就拿第一个数据去移动到正在下载中数组
            YWDownloadDataTaskTool *dataTaskTool2 = self.waitingToolArray[0];
            dataTaskTool2.status.downloadType = YWDownloadType_Downloading3;
            [self.downloadingToolArray addObject:dataTaskTool2];
            [self.waitingToolArray removeObjectAtIndex:0];
            
            //处理数据库
            [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool2.status];
            
            //开启播放
            [dataTaskTool2 resumeDataTask];
             
        }
    }
    //回传block数组group
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
}

//下载一个任务失败通知
-(void)errorDownloadNote:(NSNotification *)notification{
    //拿出模型
    YWDownloadStatus3 *status = notification.userInfo[@"YWDownloadStatusKey"];

    YWDownloadDataTaskTool *dataTaskTool = [self.dataTaskToolDict objectForKey:status.VideoUrl];
    if (dataTaskTool == nil) {
        return;
    }
    
    //从数组移除任务
    //（因为它可能是暂停/等待/正在下载的时候变成下载失败、所以不能直接在数组移除、要先判断存不存在数组）
    [self removeTool:dataTaskTool fromArray:self.downloadingToolArray];
    [self removeTool:dataTaskTool fromArray:self.waitingToolArray];;
    
    //这里就不需要枚举、数据库、通知了、因为YWDownloadDataTaskTool里面的完成回调里面已经做了
    
    //失败了一个、就自动下载下一个
    if (self.downloadingToolArray.count < downloadingArrayMaxNum) {
        //前提条件是等待中数组要有数据
        if (self.waitingToolArray.count>0) {
            
            //就拿第一个数据去移动到正在下载中数组
            YWDownloadDataTaskTool *dataTaskTool2 = self.waitingToolArray[0];
            dataTaskTool2.status.downloadType = YWDownloadType_Downloading3;
            [self.downloadingToolArray addObject:dataTaskTool2];
            [self.waitingToolArray removeObjectAtIndex:0];
            
            //处理数据库
            [YWDownloadDataBaseTool updateDownloadingStatus:dataTaskTool2.status];
            
            //开启播放
            [dataTaskTool2 resumeDataTask];
             
        }
    }
    //回传block数组group
    if (self.groupArrayBlock) {
        self.groupArrayBlock(self.group);
    }
}


//从数组移除模型方法
-(void)removeTool:(YWDownloadDataTaskTool *)tool fromArray:(NSMutableArray <YWDownloadDataTaskTool *>*)mArray{
    
    [mArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        YWDownloadDataTaskTool *downloadTool = (YWDownloadDataTaskTool *)obj;

        if ([downloadTool.status.VideoUrl isEqualToString:tool.status.VideoUrl]){

             [mArray removeObject:downloadTool];
            *stop = YES;

        }
    }];
    
}


//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//---//------//---//---//---//---//


- (instancetype)init
{
    self = [super init];
    if (self) {
       
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(finishDownloadNote:) name:YWFinishDownloadNote object:nil];
        
             [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(errorDownloadNote:) name:YWErrorDownloadNote object:nil];
    }
    return self;
}

-(NSMutableArray*)group{
    if (_group == nil) {
        _group = [NSMutableArray array];
        
        YWSectionGroupStatus *sectionStatus0 = [[YWSectionGroupStatus alloc] init];
        sectionStatus0.headerTitle = @"     正在下载";
        sectionStatus0.remark = 0;
        
        YWSectionGroupStatus *sectionStatus1 = [[YWSectionGroupStatus alloc] init];
        sectionStatus1.headerTitle = @"     下载完成";
        sectionStatus1.remark = 1;
        
        [_group addObject:sectionStatus0];
        [_group addObject:sectionStatus1];
        
    }
    return _group;
}


-(NSMutableDictionary *)dataTaskToolDict{
    if (_dataTaskToolDict == nil) {
        _dataTaskToolDict = [NSMutableDictionary dictionary];
    }
    return _dataTaskToolDict;
}

-(NSMutableArray *)downloadingToolArray{
    if (_downloadingToolArray == nil) {
        _downloadingToolArray = [NSMutableArray array];
    }
    return _downloadingToolArray;
}

-(NSMutableArray *)waitingToolArray{
    if (_waitingToolArray == nil) {
        _waitingToolArray = [NSMutableArray array];
    }
    return _waitingToolArray;
}

//判断这个模型存不存在数据库
+(void)judgeStatusExistInDataBase:(NSString *)videoUrl ifNoExist:(void(^)(void))ifNoExist{
    
    YWDownloadStatus3 *downloadStatus = [YWDownloadDataBaseTool getFinishStatusWithVideoUrl:videoUrl];
    
    if (downloadStatus == nil) {
        
        downloadStatus = [YWDownloadDataBaseTool getDownloadingStatusWithVideoUrl:videoUrl];
        
        //假如正在下载数据库也不存在，那么可以把存入来的模型加进数据库了
        if (downloadStatus == nil) {
            
            if (ifNoExist) {
                ifNoExist();
            }
            
        }
      
    }
    
}


//判断这个模型存不存在数据库2
+(void)judgeStatusExistInFinishDataBase:(NSString *)videoUrl ifExist:(void(^)(YWDownloadStatus3 *))existStatusBlock ifNoExist:(void(^)(void))ifNoExist{
    
    YWDownloadStatus3 *downloadStatus = [YWDownloadDataBaseTool getFinishStatusWithVideoUrl:videoUrl];
    
    if (downloadStatus == nil) {
        
        if (ifNoExist) {
            ifNoExist();
        }
      
    }
    else{
        
        if (existStatusBlock) {
            existStatusBlock(downloadStatus);
        }
    }
    
    
}



-(void)dealloc{
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


//获取正在任务中的数量有多少个
-(NSInteger)getDownloadingTaskCount{
    
    YWSectionGroupStatus *sectionStatus0 = self.group[0];
    return sectionStatus0.statusArray.count;
}





@end
